#include "pch.h"
#include "GameCanvas.h"

HWND GameCanvas::hwnd = nullptr;

void GameCanvas::Reset()
{
	ThrowIfFailed(m_commandAllocator->Reset());

	ThrowIfFailed(m_commandList->Reset(m_commandAllocator.Get(), m_pipelineState));
}

GameCanvas::GameCanvas(HWND hwnd, int width, int height) :
	m_viewport(0.0f, 0.0f, static_cast<float>(width), static_cast<float>(height)),
	m_scissorRect(0, 0, static_cast<LONG>(width), static_cast<LONG>(height))
{
	m_deviceWrapper = new D3D12DeviceWrapper(hwnd, width, height);
	m_graphicsMemory = std::make_unique<GraphicsMemory>(m_deviceWrapper->GetDevice());

	//m_graphicsMemory->Allocate();
	//m_graphicsMemory->AllocateConstant();

	m_deviceWrapper->CreateCommandList(m_commandAllocator, m_commandList);
	m_deviceWrapper->CreateCommandList(m_commandAllocator1, m_commandList1);
	NAME_D3D12_OBJECT(m_commandList1);
	NAME_D3D12_OBJECT(m_commandList);

	m_commandQueue = m_deviceWrapper->GetCommandQueue();
	m_commandList->Close();
	m_commandList1->Close();

	RenderTargetState rtState(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_D32_FLOAT);

	EffectPipelineStateDescription pd(
		nullptr,
		CommonStates::Opaque,
		CommonStates::DepthDefault,
		CommonStates::CullClockwise,
		rtState);
	EffectPipelineStateDescription pdAlpha(
		nullptr,
		CommonStates::AlphaBlend,
		CommonStates::DepthDefault,
		CommonStates::CullClockwise,
		rtState);

	wchar_t filename[200];
	UINT bufferSize = sizeof(filename);
	GetFullPathName(L"1.sdkmesh", 200, filename, NULL);
	m_model = Model::CreateFromSDKMESH(m_deviceWrapper->GetDevice(), filename);

	GetFullPathName(L"2.sdkmesh", 200, filename, NULL);
	m_model1 = Model::CreateFromSDKMESH(m_deviceWrapper->GetDevice(), filename);

	m_states = std::make_unique<CommonStates>(m_deviceWrapper->GetDevice());

	ResourceUploadBatch resourceUpload(m_deviceWrapper->GetDevice());
	resourceUpload.Begin();
	m_model->LoadStaticBuffers(m_deviceWrapper->GetDevice(), resourceUpload);
	m_model1->LoadStaticBuffers(m_deviceWrapper->GetDevice(), resourceUpload);
	size_t ms = m_model->textureNames.size();
	size_t ms1 = m_model1->textureNames.size();
	m_modelResources = std::make_unique<EffectTextureFactory>(
		m_deviceWrapper->GetDevice(),
		resourceUpload,
		ms + ms1,
		D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE);

	//m_modelResources = m_model->LoadTextures(m_deviceWrapper->GetDevice(), resourceUpload);
	m_model->LoadTextures(*m_modelResources);
	m_model1->LoadTextures(*m_modelResources, ms);


	auto uploadResourcesFinished1 = resourceUpload.End(m_commandQueue);
	uploadResourcesFinished1.wait();
	m_srvHeap = m_modelResources->Heap();
	//m_srvHeap = m_modelResources->Heap();
	m_fxFactory = std::make_unique<EffectFactory>(m_srvHeap, m_states->Heap());

	m_modelNormal = m_model->CreateEffects(*m_fxFactory, pd, pdAlpha);
	m_modelNormal1 = m_model1->CreateEffects(*m_fxFactory, pd, pdAlpha, ms);


	m_world = Matrix::Identity;

	m_view = Matrix::CreateLookAt(m_eye,
		Vector3::Zero, Vector3::UnitY);
	m_proj = Matrix::CreatePerspectiveFieldOfView(XM_PI / 4.f,
		float(800) / float(600), 0.1f, 10.f);


}

GameCanvas::~GameCanvas()
{

}

void GameCanvas::Render()
{
	Reset();

	ID3D12DescriptorHeap* heaps[] = { m_srvHeap, m_states->Heap() };
	m_commandList->SetDescriptorHeaps(_countof(heaps), heaps);

	m_commandList->RSSetViewports(1, &m_viewport);
	m_commandList->RSSetScissorRects(1, &m_scissorRect);

	ID3D12Resource* rt = m_deviceWrapper->GetRenderTargetResource();
	m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rt, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET));

	CD3DX12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_deviceWrapper->GetRenderTargetHandle();
	CD3DX12_CPU_DESCRIPTOR_HANDLE dsvHandle(m_deviceWrapper->GetDepthStencilHeap()->GetCPUDescriptorHandleForHeapStart());
	m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, &dsvHandle);

	const float clearColor[] = { 0.5f, 0.2f, 0.4f, 1.0f };
	m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
	m_commandList->ClearDepthStencilView(dsvHandle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);

	Model::UpdateEffectMatrices(m_modelNormal, m_world, m_view, m_proj);
	m_model->Draw(m_commandList.Get(), m_modelNormal.cbegin());
	//auto tran = m_world.CreateScale({ 0.1,0.1,0.1 });
	//Model::UpdateEffectMatrices(m_modelNormal, m_world* tran, m_view, m_proj);

	//m_model->Draw(m_commandList, m_modelNormal.cbegin());
	//auto tran = m_world.CreateScale({ 0.1,0.1,0.1 });

	Model::UpdateEffectMatrices(m_modelNormal1, m_world , m_view, m_proj);
	m_model1->Draw(m_commandList.Get(), m_modelNormal1.cbegin());

	m_commandList->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(rt, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT));
	m_commandList->Close();

	ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() };

	//m_deviceWrapper->PostCommand(m_commandList);
	m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
	m_deviceWrapper->Present();
	m_graphicsMemory->Commit(m_commandQueue);
}

void GameCanvas::KeyDown(UINT8 key)
{
	switch (key) {
	case VK_LEFT:
	{
		float x = m_eye.x;
		float z = m_eye.z;
		float r = sqrtf(z * z + x * x);

		m_angleH -= 0.05;
		z = r * sinf(m_angleH);
		x = r * cosf(m_angleH);

		m_eye.x = x;
		m_eye.z = z;

		m_view = Matrix::CreateLookAt(m_eye,
			Vector3::Zero, Vector3::UnitY);

	}
	break;
	case VK_RIGHT:
	{
		float x = m_eye.x;
		float z = m_eye.z;
		float r = sqrtf(z * z + x * x);

		m_angleH += 0.05;
		z = r * sinf(m_angleH);
		x = r * cosf(m_angleH);

		m_eye.x = x;
		m_eye.z = z;

		m_view = Matrix::CreateLookAt(m_eye,
			Vector3::Zero, Vector3::UnitY);

	}

	break;
	case VK_DOWN:
	{
		float x = m_eye.x;
		float y = m_eye.y;
		float r = sqrtf(y * y + x * x);

		m_angleV += 0.05;
		y = r * sinf(m_angleV);
		x = r * cosf(m_angleV);

		m_eye.x = x;
		m_eye.y = y;

		m_view = Matrix::CreateLookAt(m_eye,
			Vector3::Zero, Vector3::UnitY);

	}
	break;
	case VK_UP:
	{
		float x = m_eye.x;
		float y = m_eye.y;
		float r = sqrtf(y * y + x * x);

		m_angleV -= 0.05;
		y = r * sinf(m_angleV);
		x = r * cosf(m_angleV);

		m_eye.x = x;
		m_eye.y = y;

		m_view = Matrix::CreateLookAt(m_eye,
			Vector3::Zero, Vector3::UnitY);

	}
	break;
	}
}
